﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;

namespace Deskopeia.Helper
{
#warning check whether this class is up-to-date (compare to wintools)
#warning remove unused stuff

    public static class DwmHelper
    {
        public const int DWM_TNP_OPACITY = 4;
        public const int DWM_TNP_RECTDESTINATION = 1;
        public const int DWM_TNP_RECTSOURCE = 2;
        public const int DWM_TNP_SOURCECLIENTAREAONLY = 0x10;
        public const int DWM_TNP_VISIBLE = 8;


        [DllImport("dwmapi.dll")]
        public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE dwAttribute, ref IntPtr pvAttribute, int cbAttribute);
        [DllImport("dwmapi.dll")]
        public static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind);
        [DllImport("dwmapi.dll")]
        public static extern int DwmEnableComposition(bool fEnabled);
        [DllImport("dwmapi.dll")]
        public static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
        [DllImport("dwmapi.dll")]
        public static extern void DwmGetColorizationColor(out uint ColorizationColor, out bool ColorizationOpaqueBlend);
        [DllImport("dwmapi.dll")]
        public static extern void DwmIsCompositionEnabled(ref bool pfEnabled);
        [DllImport("dwmapi.dll")]
        public static extern int DwmQueryThumbnailSourceSize(IntPtr thumb, out PSIZE size);
        [DllImport("dwmapi.dll")]
        public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb);
        [DllImport("dwmapi.dll")]
        public static extern int DwmUnregisterThumbnail(IntPtr thumb);
        [DllImport("dwmapi.dll")]
        public static extern int DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props);

        [StructLayout(LayoutKind.Sequential)]
        public struct MARGINS
        {
            public int leftWidth;
            public int rightWidth;
            public int topHeight;
            public int bottomHeight;

            public MARGINS(int all)
            {
                leftWidth = all;
                rightWidth = all;
                topHeight = all;
                bottomHeight = all;
            }

            public MARGINS(int leftWidth, int rightWidth, int topHeight, int bottomHeight)
            {
                this.leftWidth = leftWidth;
                this.rightWidth = rightWidth;
                this.topHeight = topHeight;
                this.bottomHeight = bottomHeight;
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DWM_BLURBEHIND
        {
            public uint dwFlags;
            public bool fEnable;
            public IntPtr hRgnBlur;
            public bool fTransitionOnMaximized;

            public const uint DWM_BB_ENABLE = 1;
            public const uint DWM_BB_BLURREGION = 2;
            public const uint DWM_BB_TRANSITIONONMAXIMIZED = 4;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DWM_THUMBNAIL_PROPERTIES
        {
            public int dwFlags;
            public Win32APIImports.RECT rcDestination;
            public Win32APIImports.RECT rcSource;
            public byte opacity;
            public bool fVisible;
            public bool fSourceClientAreaOnly;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct PSIZE
        {
            public int x;
            public int y;

            public Size ToSize()
            {
                return new Size(x, y);
            }
        }

        public enum DWMWINDOWATTRIBUTE
        {
            DWMWA_NCRENDERING_ENABLED = 1,      // [get] Is non-client rendering enabled/disabled
            DWMWA_NCRENDERING_POLICY,           // [set] Non-client rendering policy
            DWMWA_TRANSITIONS_FORCEDISABLED,    // [set] Potentially enable/forcibly disable transitions
            DWMWA_ALLOW_NCPAINT,                // [set] Allow contents rendered in the non-client area to be visible on the DWM-drawn frame.
            DWMWA_CAPTION_BUTTON_BOUNDS,        // [get] Bounds of the caption button area in window-relative space.
            DWMWA_NONCLIENT_RTL_LAYOUT,         // [set] Is non-client content RTL mirrored
            DWMWA_FORCE_ICONIC_REPRESENTATION,  // [set] Force this window to display iconic thumbnails.
            DWMWA_FLIP3D_POLICY,                // [set] Designates how Flip3D will treat the window.
            DWMWA_EXTENDED_FRAME_BOUNDS,        // [get] Gets the extended frame bounds rectangle in screen space
            DWMWA_HAS_ICONIC_BITMAP,            // [set] Indicates an available bitmap when there is no better thumbnail representation.
            DWMWA_DISALLOW_PEEK,                // [set] Don't invoke Peek on the window.
            DWMWA_EXCLUDED_FROM_PEEK,           // [set] LivePreview exclusion information
            DWMWA_LAST
        }


        /// <summary>
        /// works only with activated DWM
        /// </summary>
        public static void EnableSnapForHWnd(IntPtr hWnd, bool enable)
        {
            if (hWnd != IntPtr.Zero)
            {
                IntPtr value = new IntPtr(enable ? 0 : 1);
                DwmHelper.DwmSetWindowAttribute(hWnd, DwmHelper.DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, ref value, sizeof(DwmHelper.DWMWINDOWATTRIBUTE));
            }
        }

        public static Size GetExactThumbnailSize(IntPtr sourceWindow, bool clientAreaOnly)
        {
            using (Form tmpForm = new Form())
            {
                IntPtr thumbnailHandle = DwmHelper.CreateWindowThumbnail(tmpForm.Handle, sourceWindow, tmpForm.Bounds, clientAreaOnly);
                PSIZE exactThumbnailSize = DwmHelper.GetDwmThumbnailSize(thumbnailHandle);
                UnregisterThumbnail(thumbnailHandle);
                return new Size(exactThumbnailSize.x, exactThumbnailSize.y);
            }
        }

        public static PSIZE GetDwmThumbnailSize(IntPtr thumbnailHandle)
        {
            PSIZE result = new PSIZE();
            if (IsDwmCompositionEnabled() && thumbnailHandle != IntPtr.Zero)
            {
                try
                {
                    DwmQueryThumbnailSourceSize(thumbnailHandle, out result);
                }
                catch { }
            }

            return result;
        }

        public static bool IsDwmCompositionEnabled()
        {
            bool result = false;
            DwmIsCompositionEnabled(ref result);
            return result;
        }

        public static IntPtr CreateWindowThumbnail(IntPtr parentWindow, IntPtr sourceWindow, Rectangle rect, bool clientAreaOnly)
        {
            IntPtr thumbnail = IntPtr.Zero;

            if (DwmHelper.IsDwmCompositionEnabled() && parentWindow != IntPtr.Zero && sourceWindow != IntPtr.Zero && Win32APIImports.IsWindow(sourceWindow) && Win32APIImports.IsWindow(parentWindow))
            {
                try
                {
                    int result = DwmRegisterThumbnail(parentWindow, sourceWindow, out thumbnail);
                    if (result == 0)
                        UpdateWindowThumbnail(sourceWindow, thumbnail, rect, clientAreaOnly);
                }
                catch { }
            }

            return thumbnail;
        }

        public static void UpdateWindowThumbnail(IntPtr parentWindow, IntPtr thumbnail, Rectangle rect, bool clientAreaOnly)
        {
            if (DwmHelper.IsDwmCompositionEnabled() && thumbnail != IntPtr.Zero && Win32APIImports.IsWindow(parentWindow))
            {
                try
                {
                    DWM_THUMBNAIL_PROPERTIES thumbnailProperties = new DWM_THUMBNAIL_PROPERTIES();
                    thumbnailProperties.dwFlags = DWM_TNP_SOURCECLIENTAREAONLY | DWM_TNP_VISIBLE | DWM_TNP_OPACITY | DWM_TNP_RECTDESTINATION;
                    thumbnailProperties.fSourceClientAreaOnly = clientAreaOnly;
                    thumbnailProperties.opacity = 255;
                    thumbnailProperties.fVisible = true;
                    thumbnailProperties.rcDestination = Win32APIImports.RECT.FromRectangle(rect);

                    DwmUpdateThumbnailProperties(thumbnail, ref thumbnailProperties);
                }
                catch { }
            }
        }

        public static void UnregisterThumbnail(IntPtr thumbnail)
        {
            if (DwmHelper.IsDwmCompositionEnabled() && thumbnail != IntPtr.Zero)
            {
                try
                {
                    DwmUnregisterThumbnail(thumbnail);
                }
                catch { }
            }
        }
    }
}
